﻿// -----------------------------------------------------------------------
// <copyright file="RSA.cs" company="Hewlett-Packard">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace SecutityLib
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class RSA : EncodingDecodingTech
    {
        /// <summary>
        /// Encodes the specified plain text.
        /// </summary>
        /// <param name="plainText">The plain text.</param>
        /// <param name="key">The key.</param>
        /// <returns>
        /// cipher text
        /// </returns>
        public override string Encode(string plainText, string key)
        {
            int q, p, m, e;

            string[] tempValues = plainText.Split(',');
            if (tempValues.Length != 4)
            {
                throw new Exception("You have to enter the values in this format p,q,M,e seperated by commas");
            }

            try
            {
                p = int.Parse(tempValues[0]);
            }
            catch
            {
                throw new Exception("P must be an integer value");
            }

            try
            {
                q = int.Parse(tempValues[1]);
            }
            catch
            {
                throw new Exception("Q must be an integer value");
            }

            try
            {
                m = int.Parse(tempValues[2]);
            }
            catch
            {
                throw new Exception("M must be an integer value");
            }

            try
            {
                e = int.Parse(tempValues[3]);
            }
            catch
            {
                throw new Exception("e must be an integer value");
            }

            int n = p * q;

            int result = this.GetValueOfMPowEmodN(m, e, n);

            return result.ToString();
        }

        /// <summary>
        /// Decodes the specified plain text.
        /// </summary>
        /// <param name="cipherText">The cipher text.</param>
        /// <param name="key">The key.</param>
        /// <returns>
        /// cipher text
        /// </returns>
        public override string Decode(string cipherText, string key)
        {
            int q, p, m, e;

            string[] tempValues = cipherText.Split(',');
            if (tempValues.Length != 4)
            {
                throw new Exception("You have to enter the values in this format p,q,M,e seperated by commas");
            }

            try
            {
                p = int.Parse(tempValues[0]);
            }
            catch
            {
                throw new Exception("P must be an integer value");
            }

            try
            {
                q = int.Parse(tempValues[1]);
            }
            catch
            {
                throw new Exception("Q must be an integer value");
            }

            try
            {
                m = int.Parse(tempValues[2]);
            }
            catch
            {
                throw new Exception("M must be an integer value");
            }

            try
            {
                e = int.Parse(tempValues[3]);
            }
            catch
            {
                throw new Exception("e must be an integer value");
            }

            int n = p * q;

            int d = HillCipher.EclidInverse(e, (p - 1) * (q - 1));

            int result = this.GetValueOfMPowEmodN(m, d, n);

            return result.ToString();
        }

        /// <summary>
        /// Gets the value of M pow emod N.
        /// </summary>
        /// <param name="m">The M.</param>
        /// <param name="e">The e.</param>
        /// <param name="n">The n.</param>
        /// <returns>the result using decomposition</returns>
        private int GetValueOfMPowEmodN(int m, int e, int n)
        {
            if (e == 1)
            {
                return m % n;
            }
            else if (e == 2)
            {
                return (int)Math.Pow(m, 2) % n;
            }
            else
            {
                int temp = this.GetValueOfMPowEmodN(m, e - 2, n) * this.GetValueOfMPowEmodN(m, 2, n);
                return temp % n;
            }
        }
    }
}
